import { Tween, UIOpacity, tween, v3, view } from 'cc';
import { app } from '../application';
import { ccclass } from '../decorators';
import { BaseUI } from './BaseUI';
import { BaseStack } from './BaseStack';

/**
 * - 作者: DoooReyn
 * - 日期: 2023.10.31
 * - 名称: BasePopup
 * - 描述: 弹窗基类
 */
@ccclass()
export class BasePopup extends BaseUI {
    public async close() {
        if (this._closed) return;
        
        this._closed = true;
        await app.view.popup.remove(this);
        this._closed = false;
    }

    /** 堆栈层被点击时调用（独属于弹窗的特性） */
    protected async onUIStackClicked() {}

    /**
     * 播放过渡动画
     * @param enter 是否进入动画
     * @returns
     */
    protected async playAnimation(enter: boolean): Promise<void> {
        const duration = 0.4;
        const easing = enter ? 'backOut' : 'backIn';
        const opacity = this.setupComponent(UIOpacity);
        const t1 = tween(this.node);
        const t2 = tween(opacity);
        const position = enter ? v3() : v3(0, -view.getVisibleSize().height);
        const opacityV = enter ? 255 : 0;
        return new Promise((resolve) => {
            const onComplete = () => {
                opacity.destroy();
                resolve();
            };
            Tween.stopAllByTarget(this.node);
            Tween.stopAllByTarget(opacity);
            t1.to(duration, { position }, { easing }).start();
            t2.to(duration, { opacity: opacityV }, { easing, onComplete }).start();
        });
    }

    async onWillAdd(): Promise<void> {
        await super.onWillAdd();
        this.setupComponent(UIOpacity).opacity = 0;
        this.node.setPosition(0, -view.getVisibleSize().height);
    }

    async onAdded(): Promise<void> {
        await super.onAdded();
        await this.playAnimation(true);
        this.node.on(BaseStack.EventType.Clicked, this.onUIStackClicked, this);
    }

    async onWillRemove(): Promise<void> {
        await super.onWillRemove();
        await this.playAnimation(false);
    }

    async onRemoved(): Promise<void> {
        this.node.off(BaseStack.EventType.Clicked, this.onUIStackClicked, this);
        await super.onRemoved();
    }
}
